package com.zb.framework.service.impl;

import com.zb.framework.model.LdapOu;
import com.zb.framework.model.LdapUser;
import com.zb.zeus.common.core.res.ZeusThreadPoolResources;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.ldap.NameAlreadyBoundException;
import org.springframework.ldap.NameNotFoundException;
import org.springframework.ldap.core.ContextMapper;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.query.LdapQueryBuilder;
import org.springframework.ldap.support.LdapNameBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * @author fujianjian
 * @date 2023/5/23 10:58
 **/
@Slf4j
@Service
@ConditionalOnProperty(prefix = "zeus.ldap", value = "enable", havingValue = "true")
@RequiredArgsConstructor
public class ActiveDomainServiceImpl {

    private final LdapTemplate zeusLdapTemplate;
    private final LdapTemplate zeusLdapsTemplate;
    public static String BASE;
    public static String DOMAIN_NAME;
    /**
     * 路径分隔符
     */
    public static final String SEPARATOR = "_";
    /**
     * 外部合作单位-组织前缀
     */
    public static final String EXTERNAL_ORG_PREFIX = "外部合作单位";
    /**
     * AD域根目录
     */
    public static final String AD_DOMAIN_ROOT_PATH = "巨鲸生物科技";

    private final IhrDatasourceServiceImpl ihrDatasourceService;

    public boolean adLdapUser(LdapUser ldapUser) {
        try {
            Attributes attrs = new BasicAttributes();
            BasicAttribute basicAttr = new BasicAttribute("objectclass");
            basicAttr.add("top");
            basicAttr.add("person");
            basicAttr.add("organizationalPerson");
            basicAttr.add("user");
            attrs.put(basicAttr);
            attrs.put("distinguishedName", ldapUser.getDistinguishedName());
            attrs.put("cn", ldapUser.getEmployeeName());
            attrs.put("uid", ldapUser.getEmployeeCode());
            attrs.put("description", ldapUser.getEmployeeName());
            attrs.put("displayName", ldapUser.getEmployeeName());
            attrs.put("ipPhone", ldapUser.getJobLevelName());
            attrs.put("title", ldapUser.getPositionName());
            attrs.put("sAMAccountName", ldapUser.getLoginId());
            attrs.put("userPrincipalName", String.format(DOMAIN_NAME, ldapUser.getLoginId()));
            attrs.put("wWWHomePage", ldapUser.getIdNumber());
            attrs.put("mobile", ldapUser.getMobile());
            // attrs.put("userAccountControl", "512");

            List<Object> objList = zeusLdapTemplate.search(LdapQueryBuilder.query()
                            .where("objectclass").is("organizationalPerson")
                            .and("sAMAccountName").is(ldapUser.getLoginId()),
                    new LdapObjectMap());
            if (CollectionUtils.isEmpty(objList)) {
                zeusLdapTemplate.bind(ldapUser.getDn(), null, attrs);
                log.info("distinguishedName {}", ldapUser);
            } else {
                DirContextAdapter ctx = (DirContextAdapter) objList.get(0);
                String distingName = ctx.getStringAttribute("distinguishedName");
                if (!StringUtils.equals(distingName, ldapUser.getDistinguishedName())) {
                    zeusLdapTemplate.rename(ctx.getDn(), ldapUser.getDn());
                    // this.setPwdLdapUser(ldapUser);
                    log.info("rename DN for login id:{}", ldapUser.getLoginId());

                }
            }
            return true;
        } catch (NameAlreadyBoundException nabe) {
            return false;
        } catch (NameNotFoundException nnfe) {
            nnfe.printStackTrace(System.err);
            return false;
        }
    }

    public boolean setPwdLdapUser(LdapUser ldapUser) {
        try {

            List<Object> objList = zeusLdapTemplate.search(LdapQueryBuilder.query()
                            .where("objectclass").is("organizationalPerson")
                            .and("sAMAccountName").is(ldapUser.getLoginId())
                            // .and("userAccountControl").is("546")
                    ,new LdapObjectMap());
            if (!CollectionUtils.isEmpty(objList)) {
                DirContextAdapter dirCtx = (DirContextAdapter) objList.get(0);
                ModificationItem[] mods = new ModificationItem[2];
                String pwd = ldapUser.getIdNumber().substring(ldapUser.getIdNumber().length() - 6) + "@jj";
                // System.out.println(pwd + " " + ldapUser.getDistinguishedName());
                log.warn("pwd:{}, distinguishedName:{}", pwd, ldapUser.getDistinguishedName());
                mods[1] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodePwd", createUnicodePassword(pwd)));
                mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("userAccountControl", "512"));
                // mods[2] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("dn", ldapUser.getDn()));
                // mods[3] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("distinguishedName",
                // ldapUser.getDistinguishedName()));
                zeusLdapsTemplate.modifyAttributes(dirCtx.getDn(), mods);
            } else {
                log.warn("login id {} not found", ldapUser.getLoginId());
            }

            return true;
        } catch (NameAlreadyBoundException nabe) {
            return false;
        } catch (NameNotFoundException nnfe) {
            nnfe.printStackTrace(System.err);
            return false;
        } catch (Throwable throwable) {
            throwable.printStackTrace(System.err);
            return false;
        }
    }

    public static byte[] createUnicodePassword(String password) {
        String quotedPassword = "\"" + password + "\"";
        byte[] newUnicodePassword = quotedPassword.getBytes(StandardCharsets.UTF_16LE);
        return newUnicodePassword;

    }


    public boolean adOu(LdapOu ldapOu) {
        try {
            Attributes attrs = new BasicAttributes();
            BasicAttribute basicAttr = new BasicAttribute("objectclass");
            basicAttr.add("top");
            basicAttr.add("organizationalUnit");
            attrs.put(basicAttr);
            attrs.put("distinguishedName", ldapOu.getDistinguishedName());
            attrs.put("postalCode", ldapOu.getUnitId());
            attrs.put("name", ldapOu.getUniteName());
            attrs.put("description", "org");
//        attrs.put("userAccountControl", "512");
            List<Object> objList = zeusLdapTemplate.search(LdapQueryBuilder.query()
                            .where("objectclass").is("organizationalUnit")
                            .and("distinguishedName").is(ldapOu.getDistinguishedName()),
                    new LdapObjectMap());
            if (CollectionUtils.isEmpty(objList)) {
                zeusLdapTemplate.bind(ldapOu.getDn(), null, attrs);
            }
            return true;
        } catch (NameAlreadyBoundException nabe) {
            return false;
        } catch (NameNotFoundException nnfe) {
            nnfe.printStackTrace(System.err);
            return false;
        } catch (Throwable throwable) {
            throwable.printStackTrace(System.err);
            return false;
        }
    }

    public boolean modifyOU(String distinguushName) {
        try {

//        attrs.put("userAccountControl", "512");
            List<Object> objList = zeusLdapTemplate.search(LdapQueryBuilder.query()
                            .where("objectclass").is("organizationalUnit")
                            .and("distinguishedName").is(distinguushName +","+ BASE),
                    new LdapObjectMap());
            if (!CollectionUtils.isEmpty(objList)) {
                DirContextAdapter ctx = (DirContextAdapter) objList.get(0);
                zeusLdapTemplate.rename(ctx.getDn(), LdapNameBuilder.newInstance("OU=巨鲸集团,"+distinguushName).build());
            }
            return true;
        } catch (NameAlreadyBoundException nabe) {
            return false;
        } catch (NameNotFoundException nnfe) {
            nnfe.printStackTrace(System.err);
            return false;
        } catch (Throwable throwable) {
            throwable.printStackTrace(System.err);
            return false;
        }
    }


    public void addWhaleLdapUser() {
        List<LdapUser> ldapUsers = ihrDatasourceService.fetchWhaleUser();
        for (LdapUser ldapUser : ldapUsers) {
            ZeusThreadPoolResources.executeCommonTask(() -> {
                afterCopySet(ldapUser);
                adLdapUser(ldapUser);
            });

        }
    }

    public void setPwdWhaleLdapUser() {
        List<LdapUser> ldapUsers = ihrDatasourceService.fetchWhaleUser();
        for (LdapUser ldapUser : ldapUsers) {
            ZeusThreadPoolResources.executeCommonTask(() -> {
                afterCopySet(ldapUser);
                setPwdLdapUser(ldapUser);
            });

        }
    }

    public void setPwdShanlinLdapUser() {
        List<LdapUser> ldapUsers = ihrDatasourceService.fetchShanlinUser();
        for (LdapUser ldapUser : ldapUsers) {
            ZeusThreadPoolResources.executeCommonTask(() -> {
                afterCopySet(ldapUser);
                setPwdLdapUser(ldapUser);
            });

        }
    }

    public void addWhaleLdapOu() {
        List<LdapOu> ldapOus = ihrDatasourceService.fetchLdapOu();
        for (LdapOu ldapOu : ldapOus) {
            ZeusThreadPoolResources.executeCommonTask(() -> {
                afterCopySet(ldapOu);
                adOu(ldapOu);
            });

        }
    }

    public static void init(String base, String damain) {
        BASE = base;
        DOMAIN_NAME = damain;
    }

    public void afterCopySet(LdapUser ldapUser) {

        StringBuilder path = new StringBuilder();
        //域账号
        path.append("CN=").append(ldapUser.getEmployeeName());

        //组织拼接
        if (StringUtils.isNotBlank(ldapUser.getUnitPathName())) {
            ldapUser.setUnitPathName(ldapUser.getUnitPathName().replace("外部合作单位_", ""));
            String[] unitNames = StringUtils.split(ldapUser.getUnitPathName(), SEPARATOR);
            path.append(",");
            for (int i = unitNames.length - 1; i >= 2; i--) {
                path.append("OU=").append(unitNames[i].replace("江西巨鲸生物科技有限公司", "巨鲸生物科技"));
                // path.append("OU=").append(unitNames[i]);
                if (i != 2) {
                    path.append(",");
                }
            }

            if (ldapUser.getUnitPathName().startsWith(EXTERNAL_ORG_PREFIX)) {
//                path.append(",OU=").append(OrgCnst.AD_DOMAIN_VENTURE_NAME);
//                path.append(",OU=").append(OrgCnst.VENTURE_ORG_PREFIX);
                path.append(",OU=").append(EXTERNAL_ORG_PREFIX);
            }
            path.append(",OU=").append(AD_DOMAIN_ROOT_PATH);
        }
        ldapUser.setDn(LdapNameBuilder.newInstance(path.toString()).build());
        path.append(",").append(BASE);

        ldapUser.setDistinguishedName(path.toString());
    }

    public void afterCopySet(LdapOu ldapOu) {

        StringBuilder path = new StringBuilder();
        //域账号
        // path.append("CN=").append(ldapOu.getUniteName());

        //组织拼接
        if (StringUtils.isNotBlank(ldapOu.getUnitPathName())) {
            ldapOu.setUnitPathName(ldapOu.getUnitPathName().replace("外部合作单位_", ""));
            String[] unitNames = StringUtils.split(ldapOu.getUnitPathName(), SEPARATOR);
            // path.append(",");
            for (int i = unitNames.length - 1; i > 1; i--) {
                path.append("OU=").append(unitNames[i].replace("江西巨鲸生物科技有限公司", "巨鲸生物科技"));
                // path.append("OU=").append(unitNames[i]);
                if (i != 2) {
                    path.append(",");
                }
            }

            if (ldapOu.getUnitPathName().startsWith(EXTERNAL_ORG_PREFIX)) {
//                path.append(",OU=").append(OrgCnst.AD_DOMAIN_VENTURE_NAME);
//                path.append(",OU=").append(OrgCnst.VENTURE_ORG_PREFIX);
                path.append(",OU=").append(EXTERNAL_ORG_PREFIX);
            }
            path.append(",OU=").append(AD_DOMAIN_ROOT_PATH);
        }
        ldapOu.setDn(LdapNameBuilder.newInstance(path.toString()).build());
        path.append(",").append(BASE);

        ldapOu.setDistinguishedName(path.toString());
    }

    public static class LdapObjectMap implements ContextMapper<Object> {
        @Override
        public Object mapFromContext(Object o) throws NamingException {
            return o;
        }
    }

}
